using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

namespace brainfucker
{
	// These methods are injected into all new assemblies
	public static class InjectedMethods
	{
        public static Queue<int> QueueArguments(string [] args, bool endOfArgs)
        {
            Queue<int> queue = new Queue<int>();
            foreach(string arg in args) {
                bool gotFile = false;
                if(File.Exists(arg)) {
                    try {
                        foreach(char c in File.ReadAllText(arg).ToCharArray()) {
                            queue.Enqueue((int)c);
                        }
                        gotFile = true;
                    } catch(IOException e) {
                    }
                }
                if(!gotFile) {
                   foreach(char c in arg.ToCharArray()) {
                       queue.Enqueue((int)c);
                   }
                }
            }
            if(endOfArgs && queue.Count > 0) {
                queue.Enqueue(0);
            }
            return queue;
        }
        
        public static int Read(Queue<int> queue)
        {
            if(queue.Count > 0) {
                return queue.Dequeue();
            } else {
                return Console.Read();
            }
        }
    }
    
    // These methods are injected into new embedded interpreter assemblies
    public class InjectedInterpretMethods
    {
        public static void InterpretMain(string[] args, bool endOfArgs)
        {
            Queue<int> queue = InjectedMethods.QueueArguments(args, endOfArgs);
            
            Assembly assembly = Assembly.GetExecutingAssembly();
            Stream stream = assembly.GetManifestResourceStream("source");
            StreamReader sr = new StreamReader(stream);
            string source = sr.ReadToEnd();
            sr.Close();
            stream.Close();
            
            int size, offset;
            Interpreter.Analyze(source, out size, out offset);
            Interpreter interpreter = new Interpreter(size, offset);
            interpreter.Input = new InterpreterReader(queue);
            interpreter.Interpret(source);
        }
	}
	
	public class InterpreterReader : TextReader
    {
        private Queue<int> queue;

        public InterpreterReader(Queue<int> queue)
        {
            this.queue = queue;
        }

        public override int Read ()
        {
            return InjectedMethods.Read(queue);
        }
    }
}
